﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GbmpMergeCollinerCurvesUtils.h"
#include "IPolygon.h"
#include "IPolyCurve.h"
#include "ICurve2d.h"
#include "ILine2d.h"
#include "IArc2d.h"
#include "GbmpStructureProfileSearchUtils.h"
#include "Vector2dUtils.h"
#include "AlgorithmProperty.h"
#include "Intervald.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

namespace
{
    // 计算拟合出的线的方向
    Vector2d CalculateFittingLineDir(const std::vector<Vector2d>& points,
        ICurve2d* leftCurve,
        ICurve2d* rightCurve,
        double threshold)
    {
        // 情况1：待拟合点在坐标轴上，则返回坐标轴的方向X或Y
        Intervald xInterval;
        Intervald yInterval;
        for (auto point : points)
        {
            xInterval.Set((std::min)(point.GetX(), xInterval.GetMin()), (std::max)(point.GetX(), xInterval.GetMax()));
            yInterval.Set((std::min)(point.GetY(), yInterval.GetMin()), (std::max)(point.GetY(), yInterval.GetMax()));
        }
        int size = (int)points.size();
        Vector2d AB = points[size - 1] - points[0];

        // 在X轴上
        if (!MathUtils::IsGreaterThan(yInterval.Length(), threshold, Constants::DOUBLE_EPS))
        {
            if (AB.Dot(Vector2d::UnitX) > 0)
                return Vector2d::UnitX;
            else
                return -Vector2d::UnitX;
        }
        // 在Y轴上
        if (!MathUtils::IsGreaterThan(xInterval.Length(), threshold, Constants::DOUBLE_EPS))
        {
            if (AB.Dot(Vector2d::UnitY) > 0)
                return Vector2d::UnitY;
            else
                return -Vector2d::UnitY;
        }

        // 情况2：与两侧的线垂直或平行
        Vector2d startDir = points[1] - points[0];
        startDir.Normalize();
        Vector2d endDir = points[size - 1] - points[size - 2];
        endDir.Normalize();

        // 与左边的线垂直或平行
        if (Vector2dUtils::IsPerpendicular(leftCurve->GetEndTangent(), startDir, Constants::ANGLE_EPS)
            || Vector2dUtils::IsParallel(leftCurve->GetEndTangent(), startDir, Constants::ANGLE_EPS))
        {
            return startDir;
        }
        else if (Vector2dUtils::IsPerpendicular(rightCurve->GetStartTangent(), endDir, Constants::ANGLE_EPS)
            || Vector2dUtils::IsParallel(rightCurve->GetStartTangent(), endDir, Constants::ANGLE_EPS))
        {
            return endDir;
        }

        // 情况3： 返回p[0]p[-1]
        Vector2d dir = points[size - 1] - points[0];
        dir.Normalize();

        return dir;
    }

    bool IsPointOnLine(const Vector2d& point, const ILine2d* pLine, double threshold)
    {
        Vector2d startPt = pLine->GetStartPoint();
        Vector2d norm = pLine->GetStartTangent();
        norm = GbmpStructureProfileSearchUtils::Vector2dRoatate90ClockWise(norm);
        norm.Normalize();
        double d = (startPt - point).Dot(norm);
        return fabs(d) < threshold;
    }

    // 将点拟合成直线
    void FittingPointsToLines(const std::vector<Vector2d>& points,
        ICurve2d* leftCurve,
        ICurve2d* rightCurve,
        double threshold,
        std::vector<OwnerPtr<ICurve2d>>& reslut)
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(leftCurve, L"leftCurve为空",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_VOID_UNLESS(rightCurve, L"rightCurve为空",L"GDMPLab",L"2024-03-30");

        int size = (int)points.size();
        DBG_WARN_AND_RETURN_VOID_UNLESS(size > 1, L"输入不合法",L"GDMPLab",L"2024-03-30");

        Vector2d dir = CalculateFittingLineDir(points, leftCurve, rightCurve, threshold);

        if (size <= 2
            && !(dir - Vector2d::UnitX).IsZero(Constants::DOUBLE_EPS)//不在坐标轴上
            && !(dir - Vector2d::UnitY).IsZero(Constants::DOUBLE_EPS))
        {
            OwnerPtr<ILine2d> opLine = ILine2d::Create(leftCurve->GetEndPoint(), rightCurve->GetStartPoint());
            reslut.emplace_back(TransferOwnership(opLine));
            return;
        }

        Vector2d average = Vector2d::Zero;
        double len = 0;
        for (auto& p : points)
        {
            average += p;
            len += (p - points.front()).Length();
        }
        average /= size;
        len /= 1.9;
        OwnerPtr<ILine2d> opLine = ILine2d::Create(average - len * dir, average + len * dir);

        // 连接2头的曲线
        OwnerPtr<ICurve2d> opLeftCurve = TransferOwnershipCast<ICurve2d>(leftCurve->Clone());
        bool intersect = GbmpStructureProfileSearchUtils::Curve1EndConnectCurve2Start(opLeftCurve.get(), opLine.get(), false);
        if (intersect && fabs(opLeftCurve->GetLength() - leftCurve->GetLength()) < threshold)
        {
            OwnerPtr<ICurve2d> opRightCurve = TransferOwnershipCast<ICurve2d>(rightCurve->Clone());
            intersect = GbmpStructureProfileSearchUtils::Curve1EndConnectCurve2Start(opLine.get(), opRightCurve.get(), false);
            if (intersect && fabs(opRightCurve->GetLength() - rightCurve->GetLength()) < threshold)
            {
                leftCurve->SetLimits(opLeftCurve->GetLimits());
                rightCurve->SetLimits(opRightCurve->GetLimits());
                reslut.emplace_back(TransferOwnership(opLine));
                return;
            }
            else
            {
                reslut.emplace_back(ILine2d::Create(points.front(), points.back()));
                return;
            }
        }
        else
        {
            reslut.emplace_back(ILine2d::Create(points.front(), points.back()));
            return;
        }
    }

    // 将分段共线的直线拟合成直线
    void FittingLinesToLine(std::vector<OwnerPtr<ICurve2d>>& curves,
        ICurve2d* leftCurve,
        ICurve2d* rightCurve,
        double threshold)
    {
        // 收集点(所有的起点+最后一个末点)
        std::vector<Vector2d> points;
        for (auto& pCurve : curves)
        {
            Vector2d p = pCurve->GetStartPoint();
            points.push_back(p);
        }
        // 最后一个末点
        Vector2d p = curves.back()->GetEndPoint();
        points.push_back(p);

        DBG_WARN_AND_RETURN_VOID_UNLESS((int)points.size() >= 2, L"不该出现此种情况",L"GDMPLab",L"2024-03-30");

        curves.clear();
        // 拟合
        FittingPointsToLines(points, leftCurve, rightCurve, threshold, curves);
    }

    // 曲线到直线的最大距离,pCurve2都是距离很短的线，故用两端点来判断
    double CurveToLineMaxDistance(const ICurve2d* pCurve1, const ICurve2d* pCurve2, bool isNearCurve1End)
    {
        Vector2d norm;

        if (isNearCurve1End)
            norm = pCurve1->GetEndPoint();
        else
            norm = pCurve1->GetStartPoint();

        norm = GbmpStructureProfileSearchUtils::Vector2dRoatate90ClockWise(norm);
        norm.Normalize();

        Vector2d p0;
        if (isNearCurve1End)
            p0 = pCurve1->GetEndPoint();
        else
            p0 = pCurve1->GetStartPoint();

        double d1 = fabs((pCurve2->GetStartPoint() - p0).Dot(norm));
        double d2 = fabs((pCurve2->GetEndPoint() - p0).Dot(norm));

        return d1 > d2 ? d1 : d2;
    }

    // 处理短线的分组-并使第一组不是短线
    void CurvesToGroup(std::vector<OwnerPtr<ICurve2d>>& src, double curveMergeEps, std::vector<OwnerPtr<CurveMergeNode>>& root, bool bIsArcNoise = false)
    {
        // 将短线分到一个组里
        std::vector<OwnerPtr<CurveOffsetNode>> group;
        GbmpStructureProfileSearchUtils::PolygonToCurveGroup(src, curveMergeEps, bIsArcNoise, group);

        // 确保第一组不是短线的组
        if (!group.front()->opCurve.get())
        {
            group.push_back(TransferOwnership(group.front()));
            group.erase(group.begin());
        }

        DBG_WARN_AND_RETURN_VOID_UNLESS(group.front()->opCurve.get(), L"第一组是短边?",L"GDMPLab",L"2024-03-30");

        for (int idx = 0; idx < (int)group.size(); idx++)
        {
            auto& opNode = group[idx];

            root.emplace_back(NEW_AS_OWNER_PTR(CurveMergeNode));
            root.back()->isLine = true;

            // 当前不是短线所在组
            if (opNode->opCurve)
            {
                root.back()->isLine = (nullptr != dynamic_cast<ILine2d*>(opNode->opCurve.get()));
                // 记录基线
                root.back()->m_opBaseLine = TransferOwnershipCast<ICurve2d>(opNode->opCurve->Clone());
                root.back()->curves.push_back(TransferOwnership(opNode->opCurve));
            }
            else
            {
                for (int i = 0; i < (int)opNode->noiseVector.size(); i++)
                {
                    root.back()->curves.push_back(TransferOwnership(opNode->noiseVector[i]));
                }
            }
        }

        group.clear();
    }

    bool IsAllCurvesColinearToNode(std::vector<OwnerPtr<ICurve2d>>& curves, const CurveMergeNode* pNode, double curveMergeEps)
    {
        // 距离后一组近，此处是否为临界点
        for (auto& opCur : curves)
        {
            if (!pNode->ShouldAddCurve(opCur.get(), curveMergeEps))
            {
                return false;
            }
        }
        return true;
    }

    // 将短线分配到左右两侧的组中, 返回基线是否改变
    bool AllocateShortCurves(int shortCurveIdx, std::vector<OwnerPtr<CurveMergeNode>>& group, double curveMergeEps)
    {
        int size = (int)group.size();
        DBG_WARN_AND_RETURN_UNLESS(size > 3, true, L"元素太少",L"GDMPLab",L"2024-03-30");

        CurveMergeNode* pPreNode = group[(shortCurveIdx - 1 + size) % size].get();
        CurveMergeNode* pCurNode = group[shortCurveIdx].get();
        CurveMergeNode* pNextNode = group[(shortCurveIdx + 1) % size].get();

        ICurve2d* pPreCurve = pPreNode->m_opBaseLine.get();
        ICurve2d* pNextCurve = pNextNode->m_opBaseLine.get();

        DBG_WARN_AND_RETURN_UNLESS(pPreCurve && pNextCurve && !pCurNode->curves.empty() && !pCurNode->m_opBaseLine.get(),true, L"分组错误",L"GDMPLab",L"2024-03-30");

        // 是否可以全分到前一组
        bool canAllocateFront = IsAllCurvesColinearToNode(pCurNode->curves, pPreNode, curveMergeEps);
        // 是否可以全分到后一组
        bool canAllocateBack = IsAllCurvesColinearToNode(pCurNode->curves, pNextNode, curveMergeEps);

        if (canAllocateFront && canAllocateFront)
        {
            // 分到前一组还是后一组
            if (Vector2dUtils::IsParallel(pCurNode->curves.front()->GetStartTangent(), pPreNode->m_opBaseLine->GetEndTangent(), Constants::ANGLE_EPS))
            {
                canAllocateBack = false;
                canAllocateFront = true;
            }
            else if (Vector2dUtils::IsParallel(pCurNode->curves.back()->GetEndTangent(), pNextNode->m_opBaseLine->GetStartTangent(), Constants::ANGLE_EPS))
            {
                canAllocateBack = true;
                canAllocateFront = false;
            }
        }

        if (canAllocateFront)
        {
            int idx = 0;
            while (idx < (int)pCurNode->curves.size())
            {
                pPreNode->curves.push_back(TransferOwnership(pCurNode->curves[idx]));
                idx++;
            }
            pCurNode->curves.clear();
        }
        else if (canAllocateBack)
        {
            int restSize = (int)pCurNode->curves.size() - 1;
            while (restSize >= 0)
            {
                pNextNode->curves.emplace(pNextNode->curves.begin(), TransferOwnership(pCurNode->curves[restSize]));
                restSize--;
            }
            pCurNode->curves.clear();
        }
        // 前后都有
        else
        {
            while (!pCurNode->curves.empty())
            {
                auto& opShort = pCurNode->curves[0];
                // 不能加在preNode,跳出循环，尝试加到pNextNode
                if (!pPreNode->ShouldAddCurve(opShort.get(), curveMergeEps))
                    break;
                double d1 = CurveToLineMaxDistance(pPreCurve, opShort.get(), true);
                double d2 = CurveToLineMaxDistance(pNextCurve, opShort.get(), false);

                // 距离前一组近，加到前一组
                if (d1 < d2)
                {
                    pPreNode->curves.push_back(TransferOwnership(opShort));
                    pCurNode->curves.erase(pCurNode->curves.begin());
                    continue;
                }
                else
                {
                    // 距离后一组近，此处是否为临界点（此点往后，都可以合并到nextNode中）
                    if (IsAllCurvesColinearToNode(pCurNode->curves, pNextNode, curveMergeEps))
                    {
                        int restSize = (int)pCurNode->curves.size() - 1;
                        while (restSize >= 0)
                        {
                            pNextNode->curves.emplace(pNextNode->curves.begin(), TransferOwnership(pCurNode->curves[restSize]));
                            restSize--;
                        }
                        pCurNode->curves.clear();
                        break;
                    }
                    else
                    {
                        pPreNode->curves.push_back(TransferOwnership(opShort));
                        continue;
                    }
                }
            }

            // 尝试加到后一组
            while (!pCurNode->curves.empty())
            {
                auto& opShort = pCurNode->curves.back();

                if (!pNextNode->ShouldAddCurve(opShort.get(), curveMergeEps))
                    break;

                pNextNode->curves.emplace(pNextNode->curves.begin(), TransferOwnership(opShort));
                pNextNode->curves.erase(pNextNode->curves.begin() + pNextNode->curves.size() - 1);
            }
        }

        if (pCurNode->curves.empty())
        {
            group.erase(group.begin() + shortCurveIdx);
            return false;
        }
        else
        {
            group[shortCurveIdx]->m_opBaseLine = ILine2d::Create(group[shortCurveIdx]->curves.front()->GetStartPoint(), group[shortCurveIdx]->curves.back()->GetEndPoint());
            return true;
        }
    }
}

bool CurveMergeNode::ShouldAddCurve(const ICurve2d* pCurve, double threshold) const
{
    const IArc2d* pArc1 = dynamic_cast<const IArc2d*>(m_opBaseLine.get());
    const IArc2d* pArc2 = dynamic_cast<const IArc2d*>(pCurve);

    // 圆弧-圆弧
    if (pArc1 && pArc2)
        return GbmpMergeCollinerCurvesUtils::IsTwoArcColinear(pArc1, pArc2, threshold);

    const ILine2d* pLine1 = dynamic_cast<const ILine2d*>(m_opBaseLine.get());
    const ILine2d* pLine2 = dynamic_cast<const ILine2d*>(pCurve);

    // 直线-直线
    if (pLine1 && pLine2)
        return GbmpMergeCollinerCurvesUtils::IsTwoLineColinear(pLine1, pLine2, threshold);

    // 圆弧-直线
    if (pArc1 && pLine2)
    {
        double d1 = (pLine2->GetStartPoint() - pArc1->GetCenter()).Length();
        double d2 = (pLine2->GetEndPoint() - pArc1->GetCenter()).Length();

        return MathUtils::IsLessThan(d1, threshold, Constants::DOUBLE_EPS) &&
               MathUtils::IsLessThan(d2, threshold, Constants::DOUBLE_EPS);
    }

    // 直线-圆弧
    return false;
}

void gcmp::GbmpMergeCollinerCurvesUtils::Merge(std::vector<OwnerPtr<ICurve2d>>& src, double threshold)
{
    if (src.empty() || (int)src.size() < 2)
    {
        return;
    }

    std::vector<OwnerPtr<CurveMergeNode>> group;
    // 按线的长度分组
    CurvesToGroup(src, threshold, group);

    // 过短的线是干扰，直接去除
    for (int i = 0; i < (int)group.size(); i++)
    {
        CurveMergeNode* pCurNode = group[i].get();
        // 当前组不是短线
        if (pCurNode->m_opBaseLine.get())
            continue;

        if (1 == pCurNode->curves.size()
            && !MathUtils::IsGreaterThan(pCurNode->curves.front()->GetLength(), Constants::LENGTH_EPS, Constants::DOUBLE_EPS))
        {
            group.erase(group.begin() + i);
            i--;
            continue;
        }

        int size = (int)group.size();
        CurveMergeNode* pPreNode = group[(i - 1 + size) % size].get();
        CurveMergeNode* pNextNode = group[(i + 1) % size].get();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pPreNode->m_opBaseLine.get(), L"分组错误",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_VOID_UNLESS(pNextNode->m_opBaseLine.get(), L"分组错误",L"GDMPLab",L"2024-03-30");

        OwnerPtr<ICurve2d> opPreCurve = TransferOwnershipCast<ICurve2d>(pPreNode->m_opBaseLine->Clone());
        OwnerPtr<ICurve2d> opNextCurve = TransferOwnershipCast<ICurve2d>(pNextNode->m_opBaseLine->Clone());

        double maxChange = threshold * 10;

        bool intersect = GbmpStructureProfileSearchUtils::Curve1EndConnectCurve2Start(opPreCurve.get(), opNextCurve.get(), false);
        if (intersect 
            && fabs(opPreCurve->GetLength() - pPreNode->m_opBaseLine->GetLength()) < maxChange
            && fabs(opNextCurve->GetLength() - pNextNode->m_opBaseLine->GetLength()) < maxChange)
        {
            pNextNode->m_opBaseLine = TransferOwnershipCast<ICurve2d>(opNextCurve->Clone());
            pNextNode->curves.clear();
            pNextNode->curves.push_back(TransferOwnership(opNextCurve));

            pPreNode->m_opBaseLine = TransferOwnershipCast<ICurve2d>(opPreCurve->Clone());
            pPreNode->curves.clear();
            pPreNode->curves.push_back(TransferOwnership(opPreCurve));
            group.erase(group.begin() + i);
            i--;
        }
        else
        {
            pCurNode->m_opBaseLine = ILine2d::Create(pCurNode->curves.front()->GetStartPoint(), pCurNode->curves.back()->GetEndPoint());
        }
    }

    // 确保第一组不是短线的组
    if (!group.front()->m_opBaseLine.get())
    {
        group.push_back(TransferOwnership(group.front()));
        group.erase(group.begin());
    }

    // 将能合并在一起的线分到一个组里
    if ((int)group.size() > 2)
    {
        for (int i = 0; i < (int)group.size();)
        {
            int size = (int)group.size();
            CurveMergeNode* pCurNode = group[i].get();
            CurveMergeNode* pNextNode = group[(i + 1) % size].get();

            // 当前不是短线所在组
            if (pCurNode->m_opBaseLine.get())
            {
                // nextNode不是短线
                if (pNextNode->m_opBaseLine.get())
                {
                    // 加到当前组，基线不变
                    if (pCurNode->ShouldAddCurve(pNextNode->m_opBaseLine.get(), threshold))
                    {
                        for (int idx = 0; idx < (int)pNextNode->curves.size(); idx++)
                        {
                            pCurNode->curves.push_back(TransferOwnership(pNextNode->curves[idx]));
                        }
                        pNextNode->curves.clear();
                        // 删除下一节点
                        group.erase(group.begin() + (i + 1) % size);
                    }
                    else
                    {
                        // 基线为下一组
                        i++;
                    }
                }
                else
                {
                    // next1是短线，需要确定next1中的短线是合并到curNode上还是next2上
                    if (AllocateShortCurves((i + 1) % size, group, threshold))
                        i++;
                }
            }
            else
            {
                DBG_WARN(L"短线所在组",L"GDMPLab",L"2024-03-30");
                i++;
                continue;
            }
        }
    }

    DBG_WARN_AND_RETURN_VOID_UNLESS(group.size() >= 2, L"节点太少，不能够组成环",L"GDMPLab",L"2024-03-30");
    // 第一组和最后一组合并
    if (group.front()->ShouldAddCurve(group.back()->m_opBaseLine.get(),threshold))
    {
        for (int i = 0; i < (int)group.front()->curves.size(); i++)
        {
            group.back()->curves.push_back(TransferOwnership(group.front()->curves[i]));
        }
        group.erase(group.begin());
    }
     
    if (((int)group.size()) > 2)
    {
        for (int i = 0; i < (int)group.size(); i++)
        {
            int size = (int)group.size();
            CurveMergeNode* pCurNode = group[i].get();

            CurveMergeNode* opPreNode = group[(i - 1 + size) % size].get();
            CurveMergeNode* opNextNode = group[(i + 1) % size].get();

            DBG_WARN_AND_RETURN_VOID_UNLESS(!pCurNode->curves.empty(), L"curves不该为空",L"GDMPLab",L"2024-03-30");

            ICurve2d* pLeft = opPreNode->curves.back().get();
            ICurve2d* pRight = opNextNode->curves.front().get();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pLeft, L"pLeft为空",L"GDMPLab",L"2024-03-30");
            DBG_WARN_AND_RETURN_VOID_UNLESS(pRight, L"pRight为空",L"GDMPLab",L"2024-03-30");

            // 基线是圆弧,3点构造圆弧
            if (!pCurNode->isLine)
            {
                Intervald range = pCurNode->curves.front()->GetLimits();
                Vector2d midPt = pCurNode->curves.front()->GetPoint((range.GetMax() + range.GetMin()) / 2);

                pCurNode->curves.clear();
                pCurNode->curves.push_back(
                    IArc2d::Create(pLeft->GetEndPoint(), pRight->GetStartPoint(), midPt));
            }
            else
            {
                FittingLinesToLine(pCurNode->curves, pLeft, pRight, threshold);
            }

            // 拟合出的线可以合并到后一组
            if (1 == (int)pCurNode->curves.size()
                && opNextNode->ShouldAddCurve(pCurNode->curves.front().get(), threshold))
            {
                opNextNode->curves.insert(opNextNode->curves.begin(), TransferOwnership(pCurNode->curves.front()));
                pCurNode->curves.clear();
                group.erase(group.begin() + i);
                src.clear();
                for (auto& node : group)
                {
                    for (auto& opCurve : node->curves)
                    {
                        src.emplace_back(TransferOwnership(opCurve));
                    }
                }
                return Merge(src, threshold);
            }
        }
    }

    src.clear();
    for (auto& node : group)
    {
        for (auto& opCurve : node->curves)
        {
            src.emplace_back(TransferOwnership(opCurve));
        }
    }
}

void gcmp::GbmpMergeCollinerCurvesUtils::Merge(const IPolygon* pPolygon, double curvesMergeEps, OwnerPtr<IPolygon>& result)
{
    std::vector<OwnerPtr<IPolyCurve>> allOutterLoop;
    std::vector<OwnerPtr<IPolygon>> allPolygon;
    bool ok = GbmpStructureProfileSearchUtils::GetAllDisconnectedOutterLoop(pPolygon, allOutterLoop);
    DBG_WARN_AND_RETURN_VOID_UNLESS(ok, L"获取外环失败",L"GDMPLab",L"2024-03-30");
    if (allOutterLoop.empty())
        return;
    FOR_EACH_INDEX(i, allOutterLoop)
    {
        std::vector<OwnerPtr<ICurve2d>> curves;
        allOutterLoop[i]->GetAllCurves(curves);
        DBG_WARN_AND_RETURN_VOID_UNLESS(!curves.empty(), L"curves为空",L"GDMPLab",L"2024-03-30");
        GbmpMergeCollinerCurvesUtils::Merge(curves, curvesMergeEps);
        OwnerPtr<IPolyCurve> opLoop = IPolyCurve::Create();
        for (auto& opCurve : curves)
        {
            opLoop->AddBackCurve(TransferOwnership(opCurve));
        }
        OwnerPtr<IPolygon> opPolygon = IPolygon::Create();
        opPolygon->AddPolyCurveByClone(opLoop.get());

        if (opPolygon->IsRegularized())
        {
            allPolygon.emplace_back(TransferOwnership(opPolygon));
        }
        else 
        {
            // 不合法情况忽略
        }
    }

    if (allOutterLoop.empty())
        return;

    ok = GbmpStructureProfileSearchUtils::BoolOperateUnite(allPolygon, result);
    DBG_WARN_AND_RETURN_VOID_UNLESS(ok && result.get(), L"布尔运算失败",L"GDMPLab",L"2024-03-30");
}

bool GbmpMergeCollinerCurvesUtils::IsTwoLineColinear(const ILine2d* pLine1, const ILine2d* pLine2, double curveMergeEps)
{
    if ((IsPointOnLine(pLine1->GetStartPoint(), pLine2, curveMergeEps) && IsPointOnLine(pLine1->GetEndPoint(), pLine2, curveMergeEps)) ||
    (IsPointOnLine(pLine2->GetStartPoint(), pLine1, curveMergeEps) && IsPointOnLine(pLine2->GetEndPoint(), pLine1, curveMergeEps)))
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool GbmpMergeCollinerCurvesUtils::IsTwoArcColinear(const IArc2d* pArc1, const IArc2d* pArc2, double curveMergeEps)
{
    if (MathUtils::IsGreaterThan((pArc1->GetCenter() - pArc2->GetCenter()).Length(), curveMergeEps, Constants::DOUBLE_EPS))
    {
        return false;
    }
    if (MathUtils::IsGreaterThan(fabs(pArc1->GetRadius() - pArc2->GetRadius()), curveMergeEps, Constants::DOUBLE_EPS))
    {
        return false;
    }

    return true;
}

void gcmp::GbmpMergeCollinerCurvesUtils::FilterNoiseByArea(OwnerPtr<IPolygon>& opPolygon, double dHowLongIsNoise, double dHowLargeShouldDelete)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != opPolygon, L"Invalid InputParameter!",L"GDMPLab",L"2024-03-30");

    std::vector<OwnerPtr<IPolyCurve>> opAllOutterLoop;
    int nOriginalLoopCount = opPolygon->GetPolyCurveCount();
    for (int nLoopIndex = 0; nLoopIndex < nOriginalLoopCount; nLoopIndex++)
    {
        opAllOutterLoop.push_back(TransferOwnership(opPolygon->GetPolyCurve(nLoopIndex)));
    }
    if (opAllOutterLoop.empty())
        return;

    std::vector<OwnerPtr<IPolygon>> allPolygon;
    FOR_EACH_INDEX(loopIndex, opAllOutterLoop)
    {
        bool bHasCurveDeleted = false;
        std::vector<OwnerPtr<ICurve2d>> opLoopCurves;
        opAllOutterLoop[loopIndex]->GetAllCurves(opLoopCurves);
        DBG_WARN_AND_RETURN_VOID_UNLESS(!opLoopCurves.empty(), L"opCurves为空",L"GDMPLab",L"2024-03-30");
        std::vector<OwnerPtr<CurveMergeNode>> opCurveGroups;
        // 按线的长度分组
        CurvesToGroup(opLoopCurves, dHowLongIsNoise, opCurveGroups, true);

        for (int nNodeIndex = 0; nNodeIndex < (int)opCurveGroups.size(); nNodeIndex++)
        {
            CurveMergeNode* pCurNode = opCurveGroups[nNodeIndex].get();
            if (pCurNode->m_opBaseLine.get())
                continue;    // 当前组不是短线

            int size = (int)opCurveGroups.size();
            CurveMergeNode* pPreNode = opCurveGroups[(nNodeIndex - 1 + size) % size].get();
            CurveMergeNode* pNextNode = opCurveGroups[(nNodeIndex + 1) % size].get();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pPreNode->m_opBaseLine.get(), L"分组错误",L"GDMPLab",L"2024-03-30");
            DBG_WARN_AND_RETURN_VOID_UNLESS(pNextNode->m_opBaseLine.get(), L"分组错误",L"GDMPLab",L"2024-03-30");
            ICurve2d* pPreCurveFW = pPreNode->m_opBaseLine.get();  // 共线时只修改前一条边即可
            const ICurve2d* pNextCurve = pNextNode->m_opBaseLine.get();
            if (GeometryType::Line2d == pPreCurveFW->GetType() && GeometryType::Line2d == pNextCurve->GetType())
            {
                const ILine2d* pPreLine2d = quick_cast<ILine2d>(pPreCurveFW);
                const ILine2d* pNextLine2d = quick_cast<ILine2d>(pNextCurve);
                if (IsTwoLineColinear(pPreLine2d, pNextLine2d, Constants::LENGTH_EPS) && !pCurNode->curves.empty())
                {
                    OwnerPtr<IPolyCurve> opLoop = IPolyCurve::Create();
                    for (auto& opCurve : pCurNode->curves)
                    {
                        opLoop->AddBackCurve(TransferOwnership(opCurve));
                    }

                    double dPointParam = pPreCurveFW->GetStartLimit();
                    bool bIsParamInRange = false;
                    pPreCurveFW->GetParameter(pNextCurve->GetStartPoint(), dPointParam, bIsParamInRange, Constants::LENGTH_EPS);
                    DBG_WARN_AND_CONTINUE_UNLESS(MathUtils::IsGreaterThan(dPointParam, pPreCurveFW->GetStartLimit(), Constants::LENGTH_EPS),L"参数点应该在延长段!",L"GDMPLab",L"2024-03-30");
                    if (MathUtils::IsEqual(dPointParam, pPreCurveFW->GetEndLimit(), Constants::LENGTH_EPS))
                    {
                        if (2 == opLoop->GetCurveCount() /*短边构成的环只有两条边且一端共点， 直接删除短边*/)
                        {
                            opCurveGroups.erase(opCurveGroups.begin() + nNodeIndex);    // 直接删除当前短边组
                            nNodeIndex--;
                            bHasCurveDeleted = true;
                            continue;
                        }
                    }
                    else if (MathUtils::IsGreaterThan(dPointParam, pPreCurveFW->GetEndLimit(), Constants::LENGTH_EPS))
                    {
                        opLoop->AddBackCurve(TransferOwnership(ILine2d::Create(pNextCurve->GetStartPoint(), pPreCurveFW->GetStartPoint())));
                        if (!opLoop->IsValid())
                        {
                            continue;
                        }
                        OwnerPtr<IPolygon> opPolygon = IPolygon::Create();
                        opPolygon->AddPolyCurveByClone(opLoop.get());
                        double dNoiseArea = AlgorithmProperty::GetArea(opPolygon.get());
                        if (MathUtils::IsLessThan(std::abs(dNoiseArea), dHowLargeShouldDelete, Constants::LENGTH_EPS * Constants::LENGTH_EPS))
                        {
                            pPreCurveFW->SetLimits(Intervald(pPreCurveFW->GetStartLimit(), dPointParam));
                            pPreNode->curves.clear();
                            pPreNode->curves.push_back(TransferOwnershipCast<ICurve2d>(pPreCurveFW->Clone()));
                            opCurveGroups.erase(opCurveGroups.begin() + nNodeIndex);    // 删除当前短边组
                            nNodeIndex--;
                            bHasCurveDeleted = true;
                        }
                        else
                        {
                            // 环的面积大于面积限制，不处理
                            continue;
                        }
                    }
                    else
                    {
                        // 下一条长边的起点在上一条长边的内部,异常情况不处理
                        continue;
                    }
                }
                else
                {
                    // 前后长边不共线，不处理
                    continue;
                }
            }
            else if (GeometryType::Arc2d == pPreCurveFW->GetType() && GeometryType::Arc2d == pNextCurve->GetType())
            {
                const IArc2d* pPreArc2d = quick_cast<IArc2d>(pPreCurveFW);
                const IArc2d* pNextArc2d = quick_cast<IArc2d>(pNextCurve);
                if (IsTwoArcColinear(pPreArc2d, pNextArc2d, Constants::LENGTH_EPS) && !pCurNode->curves.empty())
                {
                    OwnerPtr<IPolyCurve> opLoop = IPolyCurve::Create();
                    for (auto& opCurve : pCurNode->curves)
                    {
                        opLoop->AddBackCurve(TransferOwnership(opCurve));
                    }
                    double dPointParam = pPreCurveFW->GetStartLimit();
                    bool bIsParamInRange = false;
                    pPreCurveFW->GetParameter(pNextCurve->GetStartPoint(), dPointParam, bIsParamInRange, Constants::LENGTH_EPS);
                    DBG_WARN_AND_CONTINUE_UNLESS(MathUtils::IsGreaterThan(dPointParam, pPreCurveFW->GetStartLimit(), Constants::LENGTH_EPS),L"参数点应该在延长段!",L"GDMPLab",L"2024-03-30");
                    if (MathUtils::IsEqual(dPointParam, pPreCurveFW->GetEndLimit(), Constants::LENGTH_EPS))
                    {
                        if (2 == opLoop->GetCurveCount() /*短边构成的环只有两条边且一端共点， 直接删除短边*/)
                        {
                            opCurveGroups.erase(opCurveGroups.begin() + nNodeIndex);    // 直接删除当前短边组
                            nNodeIndex--;
                            bHasCurveDeleted = true;
                            continue;
                        }
                    }
                    else if (MathUtils::IsGreaterThan(dPointParam, pPreCurveFW->GetEndLimit(), Constants::LENGTH_EPS))
                    {
                        OwnerPtr<IArc2d> opPreCurveClone = TransferOwnershipCast<IArc2d>(pPreCurveFW->Clone());
                        opPreCurveClone->SetLimits(Intervald(pPreCurveFW->GetEndLimit(), dPointParam));
                        opPreCurveClone->Reverse();
                        opLoop->AddBackCurve(TransferOwnership(opPreCurveClone));
                        if (!opLoop->IsValid())
                        {
                            continue;
                        }
                        OwnerPtr<IPolygon> opPolygon = IPolygon::Create();
                        opPolygon->AddPolyCurveByClone(opLoop.get());
                        double dNoiseArea = AlgorithmProperty::GetArea(opPolygon.get());
                        if (MathUtils::IsLessThan(std::abs(dNoiseArea), dHowLargeShouldDelete, Constants::LENGTH_EPS * Constants::LENGTH_EPS))
                        {
                            pPreCurveFW->SetLimits(Intervald(pPreCurveFW->GetStartLimit(), dPointParam));
                            pPreNode->curves.clear();
                            pPreNode->curves.push_back(TransferOwnershipCast<ICurve2d>(pPreCurveFW->Clone()));
                            opCurveGroups.erase(opCurveGroups.begin() + nNodeIndex);    // 删除当前短边组
                            nNodeIndex--;
                            bHasCurveDeleted = true;
                            continue;
                        }
                        else
                        {
                            // 环的面积大于面积限制，不处理
                            continue;
                        }
                    }
                    else
                    {
                        // 下一条长边的起点在上一条长边的内部,异常情况不处理
                        continue;
                    }
                }
                else
                {
                    // 前后两条长边不共线，不处理
                    continue;
                }
            }
            else
            {
                // 只处理短边分组前后长边同类型的情况
                continue;
            }
        }

        if (!bHasCurveDeleted)
        {
            // 当前环中没有变被面积原则过滤，则添加原来的环
            OwnerPtr<IPolygon> opOriginalPolygon = IPolygon::Create();
            opOriginalPolygon->AddPolyCurveByClone(opAllOutterLoop[loopIndex].get());
            allPolygon.emplace_back(TransferOwnership(opOriginalPolygon));
            continue;
        }
        else
        {
            opLoopCurves.clear();
            for (auto& opNode : opCurveGroups)
            {
                for (auto& opCurve : opNode->curves)
                {
                    opLoopCurves.emplace_back(TransferOwnership(opCurve));
                }
            }
            OwnerPtr<IPolyCurve> opTmpLoop = IPolyCurve::Create();
            for (auto& opCurve : opLoopCurves)
            {
                opTmpLoop->AddBackCurve(TransferOwnership(opCurve));
            }
            OwnerPtr<IPolygon> opTmpPolygon = IPolygon::Create();
            opTmpPolygon->AddPolyCurveByClone(opTmpLoop.get());
            if (opTmpPolygon->IsRegularized())
            {
                allPolygon.emplace_back(TransferOwnership(opTmpPolygon));
            }
            else
            {
                //不合法情况忽略
            }
        }
    }

    if (allPolygon.empty() || nOriginalLoopCount != (int)allPolygon.size())
    {
        return;
    }

    bool ok = GbmpStructureProfileSearchUtils::BoolOperateUnite(allPolygon, opPolygon);
    DBG_WARN_AND_RETURN_VOID_UNLESS(ok && nullptr != opPolygon, L"布尔运算失败",L"GDMPLab",L"2024-03-30");
    return;
}
